package com.leyou.order.utils;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LeYouException;
import com.leyou.order.config.PayConfig;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.enums.PayState;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.mapper.OrderStatusMapper;
import com.leyou.order.pojo.Order;
import com.leyou.order.pojo.OrderStatus;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: Rose
 * @Date: 2021/4/13 19:26
 * @description ${description}
 * @version: 1.0.0
 */
@Component
@Slf4j
public class PayWxHelper {

    @Autowired
    private PayConfig config;

    @Autowired
    private WXPay wxPay;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderStatusMapper orderStatusMapper;

    public String createOrder(Long orderId, Long totalPay, String desc) {

        try {
            Map<String, String> data = new HashMap<>();
            // 商品描述
            data.put("body", desc);
            // 订单号
            data.put("out_trade_no", orderId.toString());
            // 金额，单位（分）
            data.put("total_fee", totalPay.toString());
            // 调用微信支付的终端iP
            data.put("spbill_create_ip", "127.0.0.1");
            // 回调地址
            data.put("notify_url", config.getNotifyUrl());
            // 交易类型为 扫码支付
            data.put("trade_type", "NATIVE");

            // 利用WxPay 工具完成下单功能
            Map<String, String> result = wxPay.unifiedOrder(data);

            // 打印结果
            for (Map.Entry<String, String> entry : result.entrySet()) {
                String key = entry.getKey();
                System.out.println(key + (key.length() >= 8 ? "\t: " : "\t\t:     ") + entry.getValue().trim());
            }

            System.out.println("==============================================");

            // 判断 通信标识和业务逻辑标识
            isSuccess(result);

            // 下单成功， 获取支付连接
            String url = result.get("code_url");

            return url;

        } catch (Exception e) {
            log.error("【微信下单】 创建预交易订单异常失败，", e);

            return null;
        }

    }

    public void isSuccess(Map<String, String> result) {
        // 判断通信标识
        String returnCode = result.get("return_code");

        if (WXPayConstants.FAIL.equals(returnCode)) {
            // 通信失败
            String returnMsg = result.get("return_msg");
            log.error("[微信支付] 统一下单API 接口 ，通信失败! 失败原因：{}", returnMsg);
            throw new LeYouException(ExceptionEnum.WX_PAY_ORDER_FAIL);
        }

        // 判断业务标识
        String resultCode = result.get("result_code");
        if (WXPayConstants.FAIL.equals(resultCode)) {
            // 下单失败
            String errorCode = result.get("err_code");
            String errorCodeDes = result.get("err_code_des");
            log.error("[微信支付] 统一下单API 接口 ，业务失败! 错误状态码：{}  ,错误原因：{}", errorCode, errorCodeDes);
            throw new LeYouException(ExceptionEnum.WX_PAY_ORDER_FAIL);
        }
    }

    /**
     * 验证签名
     *
     * @param result
     * @param result
     */
    public void isValidSign(Map<String, String> result) {
        try {
            // 重新生成签名
            String sign1 = WXPayUtil.generateSignature(result, config.getKey(), WXPayConstants.SignType.HMACSHA256);
            String sign2 = WXPayUtil.generateSignature(result, config.getKey(), WXPayConstants.SignType.MD5);
            // 和传递过来的签名进行比较
            String sign = result.get("sign");
            if (!StringUtils.equals(sign, sign2) && !StringUtils.equals(sign1, sign)) {
                //签名有误， 抛出异常
                throw new LeYouException(ExceptionEnum.INVALID_SIGN_ERROR);
            }
        } catch (Exception e) {
            log.error("[微信支付] 验证签名发生异常， 异常原因: {}", e.getMessage());
            //签名有误， 抛出异常
            throw new LeYouException(ExceptionEnum.INVALID_SIGN_ERROR);
        }
    }

    public PayState queryPayStatus(Long orderId) {
        try {
            // 组织请求参数
            Map<String, String> data = new HashMap<>();
            // 订单号
            data.put("out_trade_no", orderId.toString());
            // 查询状态
            Map<String, String> result = wxPay.orderQuery(data);

            // 校验状态码
            isSuccess(result);

            // 校验签名
            isValidSign(result);

            // 校验金额
            String totalFeeStr = result.get("total_fee");
            String orderNo = result.get("out_trade_no");
            if (org.apache.commons.lang3.StringUtils.isEmpty(totalFeeStr) || org.apache.commons.lang3.StringUtils.isEmpty(orderNo)) {
                throw new LeYouException(ExceptionEnum.INVALID_ORDER_PARAM);
            }
            // 获取结果中的金额
            Long totalFee = Long.valueOf(totalFeeStr);
            // 获取订单金额
            Long orderIdNo = Long.valueOf(orderNo);
            Order order = orderMapper.selectByPrimaryKey(orderIdNo);
            if (totalFee != order.getActualPay()) {
                // 金额不符
                throw new LeYouException(ExceptionEnum.INVALID_ORDER_PARAM);
            }

            String tradeState = result.get("trade_state");

            if (WXPayConstants.SUCCESS.equals(tradeState)) {
                // 支付成功
                // 修改订单状态
                OrderStatus orderStatus = new OrderStatus();
                orderStatus.setStatus(OrderStatusEnum.PAYED.getCode());
                orderStatus.setPaymentTime(new Date());
                orderStatus.setOrderId(orderIdNo);

                int count = orderStatusMapper.updateByPrimaryKeySelective(orderStatus);
                if (count != 1) {
                    throw new LeYouException(ExceptionEnum.UPDATE_ORDER_STATUS_ERROR);
                }

                log.info("[微信订单回调] 订单支付成功！ 订单编号：{}", orderNo);
                return PayState.SUCCESS;
            }
            //
            if ("NOTPAY".equals(tradeState) || "USERPAYING".equals(tradeState)) {
                return PayState.NOT_PAY;
            }
            return PayState.FAIL;

        } catch (Exception e) {
            return PayState.NOT_PAY;
        }
    }
}
